<template>
  <el-container class="map-layer-controller">
    <el-header height="36px">
      <div class="full-box p-a-mini flex-between f-16 b-b jsc-f-c">
        <span>图层管理</span>
        <i
          class="el-icon-close c-pointer"
          @click="$emit('close')"
        />
      </div>
    </el-header>
    <el-main>
      <div class="p-a-mini full-height overflow-auto">
        <el-tree
          ref="tree"
          :data="treeData"
          :render-content="treeRenderContent"
          :default-expanded-keys="defaultExpandedKeys"
          :default-expand-all="defaultExpandedKeys.length === 0"
          node-key="id"
        />
      </div>
    </el-main>
  </el-container>
</template>

<script>
import { layersProcessor, flattenList } from '@/store/modules/map.js'

export default {
  name: 'LayerController',
  props: {
    isGlobal: {
      type: Boolean,
      default: true
    },
    geoMap: {
      type: Object,
      default: null
    },
    appendLayers: {
      type: Array,
      default: () => []
    },
    defaultExpandedKeys: {
      type: Array,
      default: () => []
    },
    treeQueryParams: {
      type: Object,
      default: () => {}
    }
  },
  data () {
    return {
      treeData: [],
      flattenedAppendLayers: [],
      layerMap: {},
      checkedKeys: [],
      parentIndeterminateMap: {}
    }
  },
  methods: {
    async focus () {
      const defaultParams = {
        appId: 'watf',
        bzCode: 'WATF',
        node: 'ROOT',
        regExp: '',
        treeConfigId: 'WATF_LAYER_TREE',
        queryParams: {
          isHidden: '1',
          bzCode: 'WATF'
        }
      }
      this.treeData = await this.$request.post('/tree/data', !this.treeQueryParams ? defaultParams : Object.keys(this.treeQueryParams).length !== 0 ? this.treeQueryParams : defaultParams)
      this.$nextTick(() => {
        this.processTreeData()
      })
    },
    reset () {
      this.treeData = []
      this.flattenedAppendLayers = []
      this.checkedKeys = []
    },
    treeRenderContent (h, { node, data, store }) {
      return (
        <div class="custom-tree-node flex-ai-c">
          <el-checkbox
            class="p-r-tiny"
            disabled={data.att2 === '0'}
            value={this.checkedKeys.includes(data.id)}
            vOn:click_native={(e) => e.stopPropagation() }
            onChange={(value) => this.handleCheckNode(data, value)}
            indeterminate={data.att1 === '0' ? this.parentIndeterminateMap[data.id] : false}
          ></el-checkbox>
          {
            <span class="custom-tree-node-content">
              {
                data.att1 === '0' ? <BKSvgIcon icon-class="svg-sys-folder" class="c-white f-20"></BKSvgIcon> : null
              }
              {
                data.att1 === '1'
                  ? <BKSvgIcon icon-class={data.iconCls ? data.iconCls : 'svg-sys-layer'} class="c-white f-20"></BKSvgIcon>
                  : null
              }
              <span class="my-layer-name">{ node.label }</span>
            </span>
          }
        </div>
      )
    },
    handleCheckNode (data, checked) {
      const parent = this.flattenedTreeData.find(item => item.id === data.fid)
      // 互斥节点
      if (parent && parent.att2 === '0' && checked) {
        for (const child of parent.children) {
          const index = this.checkedKeys.findIndex(c => c === child.id)
          if (index !== -1) {
            this.checkedKeys.splice(index, 1)
          }
        }
      }
      this.recursiveSetNodeCheckState(data, checked)
      this.updateParentIndeterminate()
      this.changeLayerVisible()
    },
    recursiveSetNodeCheckState (data, checked) {
      if (checked) {
        !this.checkedKeys.includes(data.id) && this.checkedKeys.push(data.id)
      } else {
        const index = this.checkedKeys.findIndex(item => item === data.id)
        if (index !== -1) {
          this.checkedKeys.splice(index, 1)
        }
      }
      if (data.children && data.children.length) {
        for (const item of data.children) {
          this.recursiveSetNodeCheckState(item, checked)
        }
      }
    },
    updateParentIndeterminate () {
      for (const id in this.parentIndeterminateMap) {
        if (Object.hasOwnProperty.call(this.parentIndeterminateMap, id)) {
          const children = this.flattenedTreeData.find(item => item.id === id)?.children
          if (children && children.length) {
            let count = 0
            for (const child of children) {
              this.checkedKeys.includes(child.id) && count++
            }
            if (count === children.length) {
              // 全部选中
              !this.checkedKeys.includes(id) && this.checkedKeys.push(id)
              this.parentIndeterminateMap[id] = false
            } else {
              // 部分选中时先去除父节点选中状态
              const index = this.checkedKeys.findIndex(item => item === id)
              if (index !== -1) {
                this.checkedKeys.splice(index, 1)
              }
              this.parentIndeterminateMap[id] = count > 0
            }
          }
        }
      }
    },
    async processTreeData () {
      if (this.appendLayers && this.appendLayers.length) {
        this.appendLayersToTree()
      }
      // list: 展平后的数据 layers: 展平后再过滤之后的数据（全部都是图层）
      const { layers, list } = layersProcessor(this.treeData)
      this.flattenedTreeData = list
      // 初始化父节点的选中数组
      const parentIndeterminateMap = {}
      list.filter(item => item.att1 === '0').forEach(item => {
        parentIndeterminateMap[item.id] = false
      })
      this.parentIndeterminateMap = parentIndeterminateMap
      // 初始化图层map
      const layerMap = {}
      layers.forEach(item => {
        layerMap[item.bklayerId] = item
      })
      this.layerMap = layerMap
      for (const id in this.layerMap) {
        if (Object.hasOwnProperty.call(this.layerMap, id)) {
          await this.addCheckedKey(id)
        }
      }
      if (this.appendLayers && this.appendLayers.length) {
        for (const item of this.appendList) {
          await this.addCheckedKey(item.id)
        }
      }
      this.updateParentIndeterminate()
    },
    appendLayersToTree () {
      const subtree = []
      this.transformAppendLayerData(this.appendLayers, subtree)
      const result = []
      flattenList(subtree, result)
      this.flattenedAppendLayers = result.filter(item => item.att1 === '1')
      for (const item of subtree) {
        this.$refs.tree.append(item)
      }
    },
    transformAppendLayerData (layers, target = []) {
      for (const item of layers) {
        if (!item.att1) {
          const { bklayerId, bklayerName, bklayerGroupId } = item
          // 还原树所需要的最简单程度的结构
          target.push({
            fid: bklayerGroupId,
            id: bklayerId,
            att1: '1',
            label: bklayerName,
            layer: item
          })
        } else {
          if (item.children) {
            target.push({
              ...item,
              children: []
            })
            this.transformAppendLayerData(item.children, target[target.length - 1].children)
          }
        }
      }
    },
    async addCheckedKey (id) {
      let layer = null
      if (this.isGlobal) {
        layer = await this.$mapManager.invokeUtils('getLayer', id)
      } else if (this.geoMap) {
        layer = this.geoMap.map1.mapUtil.getLayer(id)
      }
      if (layer && layer.getVisible() && !this.checkedKeys.includes(id)) {
        this.checkedKeys.push(id)
      }
    },
    async changeLayerVisible () {
      const list = Object.keys(this.layerMap)
      if (this.isGlobal) {
        await this.$mapManager.invoke('setLayerVisible', list.join(','), false)
        await this.$mapManager.invoke('setLayerVisible', this.checkedKeys.join(','), true)
      } else if (this.geoMap) {
        this.geoMap.setLayerVisible(list.join(','), false)
        this.geoMap.setLayerVisible(this.checkedKeys.join(','), true)
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.el-container.map-layer-controller {
  position: absolute;
  top: 0;
  border-radius: 4px;
  width: 230px;
  height: auto;
  max-height: 800px;
  box-shadow: 0 0 1px 0 #1b2a3db8 !important;

  ::v-deep {
    .el-checkbox .el-checkbox__inner {
      background: rgb(255 255 255) !important;
      border-color: #a1a4a7 !important;
    }

    .el-checkbox__input.is-indeterminate .el-checkbox__inner,
    .el-checkbox.is-checked .el-checkbox__inner {
      border-color: #028df7 !important;
      background: #23a0fd !important;
    }

    .el-tree {
      background: transparent;
      color: #424e61;
      font-size: 14px;

      .el-tree-node__content {
        background: transparent;
      }

      .expanded.el-tree-node__expand-icon.el-icon-caret-right {
        color: #424e61;
      }
    }

    .custom-tree-node {
      .custom-tree-node-content {
        display: flex;
        align-items: center;
        .svg-icon.c-white { color: #959ca7; }
      }

      .my-layer-name {
        line-height: 1;
        border-radius: 4px;
        padding: 4px 10px 4px 5px;
        transition: background 0.2s;

        &:hover {
          background: rgba(21, 120, 255, 0.3);
        }
      }
    }

    .is-current > .el-tree-node__content > .custom-tree-node {
      background: transparent;
    }
  }
}
</style>
